<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.1">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/dute_favicon_32x32.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/dute_favicon_16x16.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">
  <link rel="manifest" href="/images/manifest.json">
  <meta name="msapplication-config" content="/images/browserconfig.xml">
  <meta http-equiv="Cache-Control" content="no-transform">
  <meta http-equiv="Cache-Control" content="no-siteapp">
  <meta name="google-site-verification" content="mpI5dkydstZXl6UcDCppqktXK0bbvqdZ6LkZ3KNk4Iw">
  <meta name="baidu-site-verification" content="code-a1LksZX2Ds">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"whitestore.top","root":"/","scheme":"Gemini","version":"7.8.0","exturl":true,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":true,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":true,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="如何快捷简单的使用钉钉机器人">
<meta property="og:type" content="article">
<meta property="og:title" content="钉钉机器人简单使用">
<meta property="og:url" content="https://whitestore.top/2021/02/14/dingding/index.html">
<meta property="og:site_name" content="爱看书的阿东">
<meta property="og:description" content="如何快捷简单的使用钉钉机器人">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173000.png?ynotemdtimestamp=1613223296738">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173037.png?ynotemdtimestamp=1613223296738">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173121.png?ynotemdtimestamp=1613223296738">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173313.png?ynotemdtimestamp=1613223296738">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173703.png?ynotemdtimestamp=1613223296738">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213175804.png?ynotemdtimestamp=1613223296738">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213180638.png?ynotemdtimestamp=1613223296738">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173435.png?ynotemdtimestamp=1613223296738">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213180959.png?ynotemdtimestamp=1613223296738">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213185434.png?ynotemdtimestamp=1613223296738">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213230526.png?ynotemdtimestamp=1613223296738">
<meta property="og:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213230806.png?ynotemdtimestamp=1613223296738">
<meta property="article:published_time" content="2021-02-14T03:40:42.000Z">
<meta property="article:modified_time" content="2023-07-16T06:28:09.275Z">
<meta property="article:author" content="阿东">
<meta property="article:tag" content="钉钉">
<meta property="article:tag" content="机器人">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173000.png?ynotemdtimestamp=1613223296738">

<link rel="canonical" href="https://whitestore.top/2021/02/14/dingding/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>钉钉机器人简单使用 | 爱看书的阿东</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/atom.xml" title="爱看书的阿东" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">爱看书的阿东</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">赐他一块白色石头，石头上写着新名</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-fw fa-home"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-fw fa-tags"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-fw fa-th"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-fw fa-archive"></i>归档</a>

  </li>
        <li class="menu-item menu-item-sitemap">

    <a href="/sitemap.xml" rel="section"><i class="fa fa-fw fa-sitemap"></i>站点地图</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    

  <span class="exturl github-corner" data-url="aHR0cHM6Ly9naXRodWIuY29tL2xhenlUaW1lcw==" title="Follow me on GitHub" aria-label="Follow me on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></span>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://whitestore.top/2021/02/14/dingding/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="阿东">
      <meta itemprop="description" content="随遇而安">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="爱看书的阿东">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          钉钉机器人简单使用
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2021-02-14 11:40:42" itemprop="dateCreated datePublished" datetime="2021-02-14T11:40:42+08:00">2021-02-14</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2023-07-16 14:28:09" itemprop="dateModified" datetime="2023-07-16T14:28:09+08:00">2023-07-16</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E5%85%B6%E4%BB%96/" itemprop="url" rel="index"><span itemprop="name">其他</span></a>
                </span>
            </span>

          
            <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv" style="display: none;">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span id="busuanzi_value_page_pv"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="fa fa-comment-o"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2021/02/14/dingding/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2021/02/14/dingding/" itemprop="commentCount"></span>
    </a>
  </span>
  
  <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="fa fa-file-word-o"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>44k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="fa fa-clock-o"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>40 分钟</span>
            </span>
            <div class="post-description">如何快捷简单的使用钉钉机器人</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="钉钉自定义机器人简单使用"><a href="#钉钉自定义机器人简单使用" class="headerlink" title="钉钉自定义机器人简单使用"></a>钉钉自定义机器人简单使用</h1><h1 id="前言："><a href="#前言：" class="headerlink" title="前言："></a>前言：</h1><p>年前公司的需求里面有用到钉钉机器人，使用之后发现真的非常简单，不得不感叹阿里的牛逼，这篇文章总结了一下个人使用钉钉机器人的经验，同时介绍个人据此构建一个工具类来方便后续直接“开箱即用”，希望对于读者有所启发。</p>
<a id="more"></a>

<h1 id="文章目的："><a href="#文章目的：" class="headerlink" title="文章目的："></a>文章目的：</h1><ol>
<li>简单的说明一下钉钉自定义机器人使用，注意是自定义机器人</li>
<li>说明一下个人针对钉钉机器人设计了一个工具类，说明一下设计的思路。（重点）</li>
<li>汇总一些个人使用钉钉机器人的小坑，同时提供解决办法希望读者参考可以解决问题</li>
</ol>
<h1 id="钉钉文档："><a href="#钉钉文档：" class="headerlink" title="钉钉文档："></a>钉钉文档：</h1><p>机器人的使用还是非常简单的，直接参考文档就可以进行构建，如果了解过这一部分可以直接跳到编写工具类的部分进行文章的后续阅读。</p>
<p><span class="exturl" data-url="aHR0cHM6Ly9kZXZlbG9wZXJzLmRpbmd0YWxrLmNvbS9kb2N1bWVudC9hcHAvY3VzdG9tLXJvYm90LWFjY2Vzcw==" title="https://developers.dingtalk.com/document/app/custom-robot-access">https://developers.dingtalk.com/document/app/custom-robot-access<i class="fa fa-external-link"></i></span></p>
<blockquote>
<p>由于钉钉的官方文档更新较为频繁，这里的连接可能在以后会失效</p>
</blockquote>
<h1 id="如何创建一个机器人"><a href="#如何创建一个机器人" class="headerlink" title="如何创建一个机器人"></a>如何创建一个机器人</h1><p>文档里面介绍的比较详细了，我们根据文档的内容进行实战一下即可。这里使用了 <strong>新手体验群</strong> 创建的机器人进行实验。下面的内容包括创建自定义机器人以及测试机器人如何使用。</p>
<h2 id="创建一个自定义机器人"><a href="#创建一个自定义机器人" class="headerlink" title="创建一个自定义机器人"></a>创建一个自定义机器人</h2><p>随意点击一个机器人，右击菜单，出现“更多机器人”，进入到界面</p>
<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173000.png?ynotemdtimestamp=1613223296738" alt="img"></p>
<p>点击“更多机器人”</p>
<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173037.png?ynotemdtimestamp=1613223296738" alt="img"></p>
<p>选择钉钉的自定义机器人进行使用：</p>
<blockquote>
<p>这里还有很多其他的机器人，如果感兴趣可以查看钉钉的文档进行更多的了解</p>
</blockquote>
<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173121.png?ynotemdtimestamp=1613223296738" alt="img"></p>
<p>在下面的界面选择添加：</p>
<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173313.png?ynotemdtimestamp=1613223296738" alt="img"></p>
<p>到达下一个界面，根据指示需要填写如下的内容：</p>
<ul>
<li>机器人的名称：自己取一个合适的名字，自己喜欢就行</li>
<li>添加到群组：<strong>关键</strong>的一步，意味着你的机器人要添加到哪一个具体的群组里面进行使用。也意味着只有在这个群组里面的人才可以收到对应的通知。</li>
</ul>
<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173703.png?ynotemdtimestamp=1613223296738" alt="img"></p>
<p>下面说明一下安全设置的内容：</p>
<ul>
<li>自定义关键词：<strong>关键配置</strong>，这里自定义关键词可以按照自己的喜好进行设置。但是一旦设置在发送请求的时候<strong>必须要携带关键词</strong>，请求才会生效，否则会返回对应的错误码<code>31000</code>和对应的错误信息。</li>
<li>加签：<strong>建议勾上</strong>，这里加签可以在请求中更好的保护接口，同时注意一下加上签名之后要复制一下内容</li>
<li><strong>IP地址（段）</strong>：这里个人没有进行过测试，所以没有进行勾选，正式的生产环境建议使用IP限制，保证万无一失</li>
</ul>
<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213175804.png?ynotemdtimestamp=1613223296738" alt="img"></p>
<blockquote>
<p>这里建议保存一下前面和关键字，当然忘记了也可以在构建完成之后从设置里面查看：</p>
<p>签名：<code>SECf075e3890b7d79ca645e51b42644fc57c2402577d5a955bce51cb980cec0a3b6</code></p>
<p>关键词：<code>新人</code></p>
</blockquote>
<p>至此，我们成功创建了一个钉钉的自定义机器人，整个过程十分简单，这里记得保存一下对应的信息：</p>
<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213180638.png?ynotemdtimestamp=1613223296738" alt="img"></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send?access_token&#x3D;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050</span><br></pre></td></tr></table></figure>

<p>上面为个人的配置。发文的时候此机器人<strong>已经删除</strong>，所以读者自己实验即可。</p>
<h2 id="测试机器人是否可以正常使用"><a href="#测试机器人是否可以正常使用" class="headerlink" title="测试机器人是否可以正常使用"></a>测试机器人是否可以正常使用</h2><p>通过上面的步骤，我们已经构建了一个基本的机器人为我们使用，再进行下一步之前，我们需要验证一下钉钉机器人是否可以正常使用。这里针对不同的平台说下比较简单快捷的验证方法。</p>
<h3 id="windows-验证方式："><a href="#windows-验证方式：" class="headerlink" title="windows 验证方式："></a>windows 验证方式：</h3><p>windows 推荐使用<code>git</code>的一个<code>shell</code>命令框进行测试，因为windows 本身是没有<code>curl</code>这个命令的，当然也有其他的办法，但是为了图省事直接使用<code>git</code>给我们开发的一个小工具即可。</p>
<p>如下图所示，我们选择<code>Git Bash Here</code>，打开命令行的界面</p>
<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213173435.png?ynotemdtimestamp=1613223296738" alt="img"></p>
<p>我们根据上一步的机器人配置，构建一个<code>CURL</code>请求进行测试：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">curl &#39;https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send?access_token&#x3D;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&amp;timestamp&#x3D;1613211530113&amp;secret&#x3D;SEC2e67120c5e4affa1177ac25fe8dc77ba1c5b49284a9dc7e1888770bc3b76b1fc&#39; \</span><br><span class="line">   -H &#39;Content-Type: application&#x2F;json&#39; \</span><br><span class="line">   -d &#39;&#123;&quot;msgtype&quot;: &quot;text&quot;,&quot;text&quot;: &#123;&quot;content&quot;: &quot;新人内容测试&quot;&#125;&#125;&#39;</span><br></pre></td></tr></table></figure>

<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213180959.png?ynotemdtimestamp=1613223296738" alt="img"></p>
<p>不出所料，这里按照官方文档给的方式<strong>验证失败</strong>了，这是为什么呢？原因有几个：</p>
<ul>
<li>加签密文：我们设置了加签，所以在请求参数里面要加入对应的<strong>签名密文</strong>，也就是在添加这一步勾选了<strong>签名</strong>这一步。</li>
<li>时间戳：请求需要传递<strong>时间戳</strong>，但是我们没有在请求参数里面附带时间戳，同时时间戳必须在<strong>系统时间的一小时之内</strong>，超过这个时间即使请求参数正确也无法通过</li>
</ul>
<blockquote>
<p>timestamp = 1613212103494 sign = MO79EJ58O9lmuQJo1dB1KGMhkZI%2BM5KkyD0NYuNe8%2B8%3D</p>
</blockquote>
<p>我们根据上面的说明修复一下，注意在URL增加了两个参数：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">curl &#39;https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send?access_token&#x3D;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&amp;timestamp&#x3D;1613212722591&amp;sign&#x3D;SsKKlkvwM%2F4tsCPE6YoGls8vgkQqWJGHYpvWbW7hTGM%3D&#39; \</span><br><span class="line">   -H &#39;Content-Type: application&#x2F;json&#39; \</span><br><span class="line">   -d &#39;&#123;&quot;msgtype&quot;: &quot;text&quot;,&quot;text&quot;: &#123;&quot;content&quot;: &quot;新人为什么你这么牛逼&quot;&#125;&#125;&#39;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>关于这一部分内容，已经汇总到“问题汇总”这一部分，如果还是感到迷惑可以参考。</p>
</blockquote>
<p>我们再次验证一下，发现<strong>依然失败</strong>，比较奇怪，个人设置的关键字在请求content里面却失败了：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">zhaoxudong@LAPTOP-MEUFMP1M MINGW64 &#x2F;d&#x2F;Users&#x2F;zhaoxudong&#x2F;Desktop</span><br><span class="line">$ curl &#39;https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send?access_token&#x3D;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&amp;timestamp&#x3D;1613212722591&amp;sign&#x3D;SsKKlkvwM%2F4tsCPE6YoGls8vgkQqWJGHYpvWbW7hTGM%3D&#39; \</span><br><span class="line">&gt;    -H &#39;Content-Type: application&#x2F;json&#39; \</span><br><span class="line">&gt;    -d &#39;&#123;&quot;msgtype&quot;: &quot;text&quot;,&quot;text&quot;: &#123;&quot;content&quot;: &quot;新人为什么你这么牛逼&quot;&#125;&#125;&#39;</span><br><span class="line">  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current</span><br><span class="line">                                 Dload  Upload   Total   Spent    Left  Speed</span><br><span class="line">100   178  100   115  100    63    991    543 --:--:-- --:--:-- --:--:--  1534</span><br><span class="line">&#123;&quot;errcode&quot;:310000,&quot;errmsg&quot;:&quot;keywords not in content, more: [https:&#x2F;&#x2F;ding-doc.dingtalk.com&#x2F;doc#&#x2F;serverapi2&#x2F;qf2nxq]&quot;&#125;</span><br></pre></td></tr></table></figure>

<p>排查问题之后发现由于windows系统默认使用了<code>gb2312</code>的编码，所以我们此时需要切换一下系统的编码，为了证明是系统编码的问题，我们先验证一下编码：</p>
<p>打开window的<code>cmd</code>窗口，我们输入<code>chcp</code>命令进入到具体的页面，可以看到下面936，百度一下发现就是<code>GB2312</code>，在请求发送的过程中被转码导致乱码。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">C:\Users\zhaoxudong&gt;chcp</span><br><span class="line">活动代码页: 936</span><br></pre></td></tr></table></figure>

<p>解决办法也比较简单，改一下整改系统的编码即可，关于设置的方法：<span class="exturl" data-url="aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3JvYmluaHVuYW4vYXJ0aWNsZS9kZXRhaWxzLzEwNjA0NzM0NQ==" title="https://blog.csdn.net/robinhunan/article/details/106047345">https://blog.csdn.net/robinhunan/article/details/106047345<i class="fa fa-external-link"></i></span></p>
<blockquote>
<p>插曲：个人在设置过后，因为编码的问题导致编辑器无法编译，经过核实发现是由于<strong>文件夹的编码乱码</strong>找不到类的问题，所以这里建议放置Java项目的时候放置到<strong>全英文</strong>的目录。所以更推荐linux的方式，可以省去很多麻烦</p>
</blockquote>
<h3 id="linux-验证方式："><a href="#linux-验证方式：" class="headerlink" title="linux 验证方式："></a>linux 验证方式：</h3><p>linux 验证比较简单，而且出问题的概率比较小，根据window内容得知最后需要<strong>三个</strong>参数才能请求成功，这里直接给出一个相似的CURL请求作为案例说明：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">curl &#39;https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send?access_token&#x3D;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&amp;timestamp&#x3D;1613212722591&amp;sign&#x3D;SsKKlkvwM%2F4tsCPE6YoGls8vgkQqWJGHYpvWbW7hTGM%3D&#39; \</span><br><span class="line">   -H &#39;Content-Type: application&#x2F;json&#39; \</span><br><span class="line">   -d &#39;&#123;&quot;msgtype&quot;: &quot;text&quot;,&quot;text&quot;: &#123;&quot;content&quot;: &quot;新人为什么你这么牛逼&quot;&#125;&#125;&#39;</span><br></pre></td></tr></table></figure>

<p>我们把这个请求放到<code>linux</code>命令行里面进行运行，如果errorcode返回0，说明请求成功：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;&quot;errcode&quot;:0,&quot;errmsg&quot;:&quot;ok&quot;&#125;</span><br></pre></td></tr></table></figure>

<p>请求成功之后，我们可以看到对应的结果：</p>
<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213185434.png?ynotemdtimestamp=1613223296738" alt="img"></p>
<blockquote>
<p>注意一下钉钉机器人不能请求过于频繁。建议限制一下每分钟的请求QPS</p>
</blockquote>
<h1 id="编写工具类"><a href="#编写工具类" class="headerlink" title="编写工具类"></a>编写工具类</h1><p>从上一节可以看到，整个钉钉机器人的构建还是十分简单的。但是使用起来不是特别的方便，个人之前有使用钉钉做过一个预警的小需求，为了后续可以直接开箱即用，自己构建了工具类，下面的部分主要说个人的工具类的设计以及个人的构建思路</p>
<blockquote>
<p>个人水平有限，工具类还有很大的改进空间，但是对于我来说暂时没有遇到使用的瓶颈。</p>
</blockquote>
<h2 id="工具类的代码地址"><a href="#工具类的代码地址" class="headerlink" title="工具类的代码地址"></a>工具类的代码地址</h2><p>这里个人的小工具类整合到了个人小项目里面，想要参考的可以直接进行下载，下面的文章代码也是来源于这个项目里面。</p>
<blockquote>
<p><strong>具体请查看：<code>com.zxd.interview.dingrobot</code>这个包</strong></p>
</blockquote>
<p>具体的代码地址：<span class="exturl" data-url="aHR0cHM6Ly9naXRlZS5jb20vbGF6eVRpbWVzL2ludGVydmlldy90cmVlL21hc3Rlci9zcmMvbWFpbi9qYXZhL2NvbS96eGQvaW50ZXJ2aWV3L2Rpbmdyb2JvdA==" title="https://gitee.com/lazyTimes/interview/tree/master/src/main/java/com/zxd/interview/dingrobot">https://gitee.com/lazyTimes/interview/tree/master/src/main/java/com/zxd/interview/dingrobot<i class="fa fa-external-link"></i></span></p>
<h2 id="构建工具类的思路"><a href="#构建工具类的思路" class="headerlink" title="构建工具类的思路"></a>构建工具类的思路</h2><p>把整个请求的流程需要的组件分为了以下的几个部分：</p>
<p><strong>构建基本的请求环境</strong>：也就是需要的请求地址，请求签名或者关键字等参数，这些参数都是必须的，否则请求无法正常运行，所以我们提出来作为<strong>环境</strong>使用。</p>
<p><strong>构建请求参数</strong>：由于钉钉支持非常多的<code>msgtype</code>也就是文本类型，个人参考了一下SDK，对应构建了一个请求的参数类，为了方便扩展，设计了一个接口进行后续的扩展和兼容。</p>
<p><strong>使用JAVA代码发送请求</strong>：本着最小依赖的原则，使用最常见的<code>HttpClient</code>进行模拟JAVA的请求发送。但是在这个基础上做了一点点的封装，方便后续扩展</p>
<ol>
<li>HttpClient的封装，将请求所需要的一些请求参数封装到一个配置对象进行管理</li>
<li>请求方法的封装，这里用了一个对象进行封装，也可以直接使用Spring封装的<code>org.springframework.web.bind.annotation.RequestMethod</code>或者直接使用枚举构建常量即可。</li>
<li>构建钉钉请求工具类：最后我们整合上面所有步骤构建一个核心请求工具类，通过环境参数构建请求URL和一些Header设置，以及构建不同的请求方法发送请求，调用HttpClient工具类进行请求发送，以及发送之后转化为结果对象等一系列操作均由该工具类完成，是本次工具类最核心的类。</li>
<li>构建钉钉的请求Msg：该对象包含了请求所支持的所有JSON参数格式对应的实体对象，根据参数格式构建对应的对象，个人利用<strong>内部类</strong>全部封装到一个对象里面，方便客户端理解调用。</li>
</ol>
<p><strong>返回请求结果</strong>：包含了错误码，错误信息，以及其他的参数等，也可以修改为直接返回字符串，由客户端决定如何处理</p>
<p><strong>请求之后返回结果</strong>：将上面的错误码或者错误信息等封装为一个简单对象进行返回，同样如果不喜欢也可以改为返回字符串的结果。</p>
<h2 id="单元测试"><a href="#单元测试" class="headerlink" title="单元测试"></a>单元测试</h2><p>在介绍正式的结果之前，我们看下结果，下面是效果截图，包含了钉钉文档里面的所有类型，包含了目前钉钉文档支持的几种主要的类型：</p>
<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213230526.png?ynotemdtimestamp=1613223296738" alt="测试结果1"></p>
<p><img src="https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210213230806.png?ynotemdtimestamp=1613223296738" alt="测试截图2"></p>
<p>下面为单元测试的代码，整个单元测试测试各种不同请求类型，调用工具包发送请求：</p>
<blockquote>
<p>注意下面的请求text里面包含了之前请求示例里面设置的关键字，没有关键字是无法请求成功的</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br></pre></td><td class="code"><pre><span class="line">import com.alibaba.fastjson.JSON;</span><br><span class="line">import org.apache.commons.codec.binary.Base64;</span><br><span class="line">import org.junit.jupiter.api.Test;</span><br><span class="line"></span><br><span class="line">import javax.crypto.Mac;</span><br><span class="line">import javax.crypto.spec.SecretKeySpec;</span><br><span class="line">import java.net.URLEncoder;</span><br><span class="line">import java.nio.charset.StandardCharsets;</span><br><span class="line">import java.util.ArrayList;</span><br><span class="line">import java.util.Arrays;</span><br><span class="line">import java.util.List;</span><br><span class="line"></span><br><span class="line">&#x2F;**</span><br><span class="line"> * @author zxd</span><br><span class="line"> * @version v1.0.0</span><br><span class="line"> * @Package : com.zxd.interview.dingrobot</span><br><span class="line"> * @Description : 钉钉机器人测试类</span><br><span class="line"> * @Create on : 2021&#x2F;2&#x2F;7 11:06</span><br><span class="line"> **&#x2F;</span><br><span class="line">public class DingRobotUtilsTest &#123;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">   	运行下面五个单元测试的结果</span><br><span class="line">    *&#x2F; </span><br><span class="line">    @Test</span><br><span class="line">    public void testAll() &#123;</span><br><span class="line">        testText();</span><br><span class="line">        testLink();</span><br><span class="line">        testMarkdown();</span><br><span class="line">        testActionCard();</span><br><span class="line">        testFeedCard();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 构建当前的系统时间戳</span><br><span class="line">     *&#x2F;</span><br><span class="line">    @Test</span><br><span class="line">    public void generateSystemCurrentTime() throws Exception &#123;</span><br><span class="line">        long currentTimeMillis &#x3D; System.currentTimeMillis();</span><br><span class="line">        String secret &#x3D; &quot;SEC2e67120c5e4affa1177ac25fe8dc77ba1c5b49284a9dc7e1888770bc3b76b1fc&quot;;</span><br><span class="line">        String sign &#x3D; generateSign(currentTimeMillis, secret);</span><br><span class="line">        System.out.println(&quot;timestamp &#x3D; &quot; + currentTimeMillis);</span><br><span class="line">        System.out.println(&quot;sign &#x3D; &quot; + sign);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 测试link类型的请求</span><br><span class="line">     *&#x2F;</span><br><span class="line">    @Test</span><br><span class="line">    public void testLink() &#123;</span><br><span class="line">        DingRobotRequest.Builder builder &#x3D; new DingRobotRequest.Builder();</span><br><span class="line">        DingRobotRequest build &#x3D; builder.secret(&quot;SEC2e67120c5e4affa1177ac25fe8dc77ba1c5b49284a9dc7e1888770bc3b76b1fc&quot;)</span><br><span class="line">                .url(&quot;https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send&quot;)</span><br><span class="line">                .accessToken(&quot;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&quot;)</span><br><span class="line">                .msg(generateLink()).build();</span><br><span class="line">        try &#123;</span><br><span class="line">            DingRobotResponseMsg dingRobotResponseMsg &#x3D; DingRobotUtils.notifyRobot(build);</span><br><span class="line">            System.err.println(JSON.toJSONString(dingRobotResponseMsg));</span><br><span class="line">        &#125; catch (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 测试text类型</span><br><span class="line">     *&#x2F;</span><br><span class="line">    @Test</span><br><span class="line">    public void testText() &#123;</span><br><span class="line">        DingRobotRequest.Builder builder &#x3D; new DingRobotRequest.Builder();</span><br><span class="line">        DingRobotRequest build &#x3D; builder.secret(&quot;SEC2e67120c5e4affa1177ac25fe8dc77ba1c5b49284a9dc7e1888770bc3b76b1fc&quot;)</span><br><span class="line">                .url(&quot;https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send&quot;)</span><br><span class="line">                .accessToken(&quot;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&quot;)</span><br><span class="line">                .msg(generateText()).build();</span><br><span class="line">        try &#123;</span><br><span class="line">            DingRobotResponseMsg dingRobotResponseMsg &#x3D; DingRobotUtils.notifyRobot(build);</span><br><span class="line">            System.err.println(JSON.toJSONString(dingRobotResponseMsg));</span><br><span class="line">        &#125; catch (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**测试markdown 类型 *&#x2F;</span><br><span class="line">    @Test</span><br><span class="line">    public void testMarkdown() &#123;</span><br><span class="line">        DingRobotRequest.Builder builder &#x3D; new DingRobotRequest.Builder();</span><br><span class="line">        DingRobotRequest build &#x3D; builder.secret(&quot;SEC2e67120c5e4affa1177ac25fe8dc77ba1c5b49284a9dc7e1888770bc3b76b1fc&quot;)</span><br><span class="line">                .url(&quot;https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send&quot;)</span><br><span class="line">                .accessToken(&quot;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&quot;)</span><br><span class="line">                .msg(generateMarkdown()).build();</span><br><span class="line">        try &#123;</span><br><span class="line">            DingRobotResponseMsg dingRobotResponseMsg &#x3D; DingRobotUtils.notifyRobot(build);</span><br><span class="line">            System.err.println(JSON.toJSONString(dingRobotResponseMsg));</span><br><span class="line">        &#125; catch (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">     &#x2F;**测试ActionCard 类型 *&#x2F;</span><br><span class="line">    @Test</span><br><span class="line">    public void testActionCard() &#123;</span><br><span class="line">        DingRobotRequest.Builder builder &#x3D; new DingRobotRequest.Builder();</span><br><span class="line">        DingRobotRequest build &#x3D; builder.secret(&quot;SEC2e67120c5e4affa1177ac25fe8dc77ba1c5b49284a9dc7e1888770bc3b76b1fc&quot;)</span><br><span class="line">                .url(&quot;https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send&quot;)</span><br><span class="line">                .accessToken(&quot;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&quot;)</span><br><span class="line">                .msg(generateActionCard()).build();</span><br><span class="line">        try &#123;</span><br><span class="line">            DingRobotResponseMsg dingRobotResponseMsg &#x3D; DingRobotUtils.notifyRobot(build);</span><br><span class="line">            System.err.println(JSON.toJSONString(dingRobotResponseMsg));</span><br><span class="line">        &#125; catch (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**测试FeedCard 类型 *&#x2F;</span><br><span class="line">    @Test</span><br><span class="line">    public void testFeedCard() &#123;</span><br><span class="line">        DingRobotRequest.Builder builder &#x3D; new DingRobotRequest.Builder();</span><br><span class="line">        DingRobotRequest build &#x3D; builder.secret(&quot;SEC2e67120c5e4affa1177ac25fe8dc77ba1c5b49284a9dc7e1888770bc3b76b1fc&quot;)</span><br><span class="line">                .url(&quot;https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send&quot;)</span><br><span class="line">                .accessToken(&quot;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&quot;)</span><br><span class="line">                .msg(generateFeed()).build();</span><br><span class="line">        try &#123;</span><br><span class="line">            DingRobotResponseMsg dingRobotResponseMsg &#x3D; DingRobotUtils.notifyRobot(build);</span><br><span class="line">            System.err.println(JSON.toJSONString(dingRobotResponseMsg));</span><br><span class="line">        &#125; catch (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private DingRobotRequestBody generateFeed() &#123;</span><br><span class="line">        List&lt;DingRobotRequestBody.FeedCard.FeedItem&gt; list &#x3D; new ArrayList&lt;&gt;();</span><br><span class="line">        DingRobotRequestBody dingRobotRequestBody &#x3D; new DingRobotRequestBody();</span><br><span class="line">        DingRobotRequestBody.FeedCard feedCard &#x3D; new DingRobotRequestBody.FeedCard();</span><br><span class="line">        DingRobotRequestBody.FeedCard.FeedItem feedItem &#x3D; new DingRobotRequestBody.FeedCard.FeedItem();</span><br><span class="line">        feedItem.setMessageURL(&quot;https:&#x2F;&#x2F;www.dingtalk.com&#x2F;&quot;);</span><br><span class="line">        feedItem.setTitle(&quot;新人时代的火车向前开&quot;);</span><br><span class="line">        feedItem.setPicURL(&quot;https:&#x2F;&#x2F;img.alicdn.com&#x2F;tfs&#x2F;TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png&quot;);</span><br><span class="line">        list.add(feedItem);</span><br><span class="line">        feedCard.setLinks(list);</span><br><span class="line">        dingRobotRequestBody.setFeedCard(feedCard);</span><br><span class="line">        dingRobotRequestBody.setMsgType(&quot;feedCard&quot;);</span><br><span class="line">        return dingRobotRequestBody;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private DingRobotRequestBody generateActionCard() &#123;</span><br><span class="line">        DingRobotRequestBody dingRobotRequestBody &#x3D; new DingRobotRequestBody();</span><br><span class="line">        DingRobotRequestBody.ActionCard actionCard &#x3D; new DingRobotRequestBody.ActionCard();</span><br><span class="line">        actionCard.setBtnOrientation(&quot;0&quot;);</span><br><span class="line">        actionCard.setSingleTitle(&quot;阅读全文&quot;);</span><br><span class="line">        actionCard.setSingleURL(&quot;https:&#x2F;&#x2F;www.dingtalk.com&#x2F;&quot;);</span><br><span class="line">        actionCard.setText(&quot;新人![screenshot](https:&#x2F;&#x2F;gw.alicdn.com&#x2F;tfs&#x2F;TB1ut3xxbsrBKNjSZFpXXcXhFXa-846-786.png) \n&quot; +</span><br><span class="line">                &quot; ### 乔布斯 20 年前想打造的苹果咖啡厅 \n&quot; +</span><br><span class="line">                &quot; Apple Store 的设计正从原来满满的科技感走向生活化，而其生活化的走向其实可以追溯到 20 年前苹果一个建立咖啡馆的计划&quot;);</span><br><span class="line">        actionCard.setTitle(&quot;乔布斯 20 年前想打造一间苹果咖啡厅，而它正是 Apple Store 的前身&quot;);</span><br><span class="line">        dingRobotRequestBody.setMsgType(&quot;actionCard&quot;);</span><br><span class="line">        dingRobotRequestBody.setActionCard(actionCard);</span><br><span class="line">        return dingRobotRequestBody;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private DingRobotRequestBody generateMarkdown() &#123;</span><br><span class="line">        DingRobotRequestBody dingRobotRequestBody &#x3D; new DingRobotRequestBody();</span><br><span class="line">        DingRobotRequestBody.MarkDown markDown &#x3D; new DingRobotRequestBody.MarkDown();</span><br><span class="line">        dingRobotRequestBody.setMsgType(&quot;markdown&quot;);</span><br><span class="line">        markDown.setTitle(&quot;杭州天气&quot;);</span><br><span class="line">        markDown.setText(&quot;新人测试 标题\n&quot; +</span><br><span class="line">                &quot;# 一级标题\n&quot; +</span><br><span class="line">                &quot;## 二级标题\n&quot; +</span><br><span class="line">                &quot;### 三级标题\n&quot; +</span><br><span class="line">                &quot;#### 四级标题\n&quot; +</span><br><span class="line">                &quot;##### 五级标题\n&quot; +</span><br><span class="line">                &quot;###### 六级标题\n&quot; +</span><br><span class="line">                &quot;\n&quot; +</span><br><span class="line">                &quot;引用\n&quot; +</span><br><span class="line">                &quot;&gt; A man who stands for nothing will fall for anything.\n&quot; +</span><br><span class="line">                &quot;\n&quot; +</span><br><span class="line">                &quot;文字加粗、斜体\n&quot; +</span><br><span class="line">                &quot;**bold**\n&quot; +</span><br><span class="line">                &quot;*italic*\n&quot; +</span><br><span class="line">                &quot;\n&quot; +</span><br><span class="line">                &quot;链接\n&quot; +</span><br><span class="line">                &quot;[this is a link](http:&#x2F;&#x2F;name.com)\n&quot; +</span><br><span class="line">                &quot;\n&quot; +</span><br><span class="line">                &quot;图片\n&quot; +</span><br><span class="line">                &quot;![](http:&#x2F;&#x2F;name.com&#x2F;pic.jpg)\n&quot; +</span><br><span class="line">                &quot;\n&quot; +</span><br><span class="line">                &quot;无序列表\n&quot; +</span><br><span class="line">                &quot;- item1\n&quot; +</span><br><span class="line">                &quot;- item2\n&quot; +</span><br><span class="line">                &quot;\n&quot; +</span><br><span class="line">                &quot;有序列表\n&quot; +</span><br><span class="line">                &quot;1. item1\n&quot; +</span><br><span class="line">                &quot;2. item2&quot;);</span><br><span class="line">        dingRobotRequestBody.setMarkDown(markDown);</span><br><span class="line">        return dingRobotRequestBody;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private DingRobotRequestBody generateText() &#123;</span><br><span class="line">        DingRobotRequestBody dingRobotRequestBody &#x3D; new DingRobotRequestBody();</span><br><span class="line">        DingRobotRequestBody.Text text &#x3D; new DingRobotRequestBody.Text();</span><br><span class="line">        text.setContent(&quot;新人为什么这么牛逼&quot;);</span><br><span class="line">        DingRobotRequestBody.At at &#x3D; getnerateAt();</span><br><span class="line">        dingRobotRequestBody.setMsgType(&quot;text&quot;);</span><br><span class="line">        dingRobotRequestBody.setAt(at);</span><br><span class="line">        dingRobotRequestBody.setText(text);</span><br><span class="line">        return dingRobotRequestBody;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private DingRobotRequestBody generateLink() &#123;</span><br><span class="line">        DingRobotRequestBody dingRobotRequestBody &#x3D; new DingRobotRequestBody();</span><br><span class="line">        DingRobotRequestBody.Link link &#x3D; new DingRobotRequestBody.Link();</span><br><span class="line">        link.setMessageUrl(&quot;https:&#x2F;&#x2F;www.dingtalk.com&#x2F;s?__biz&#x3D;MzA4NjMwMTA2Ng&#x3D;&#x3D;&amp;mid&#x3D;2650316842&amp;idx&#x3D;1&amp;sn&#x3D;60da3ea2b29f1dcc43a7c8e4a7c97a16&amp;scene&#x3D;2&amp;srcid&#x3D;09189AnRJEdIiWVaKltFzNTw&amp;from&#x3D;timeline&amp;isappinstalled&#x3D;0&amp;key&#x3D;&amp;ascene&#x3D;2&amp;uin&#x3D;&amp;devicetype&#x3D;android-23&amp;version&#x3D;26031933&amp;nettype&#x3D;WIFI&quot;);</span><br><span class="line">        link.setPicUrl(&quot;&quot;);</span><br><span class="line">        link.setTitle(&quot;时代的火车向前开&quot;);</span><br><span class="line">        link.setText(&quot;新人：这个即将发布的新版本,创始人xx称它为红树林。而在此之前,每当面临重大升级,产品经理们都会取一个应景的代号,这一次,为什么是红树林&quot;);</span><br><span class="line">        DingRobotRequestBody.At at &#x3D; getnerateAt();</span><br><span class="line">        dingRobotRequestBody.setMsgType(&quot;link&quot;);</span><br><span class="line">        dingRobotRequestBody.setAt(at);</span><br><span class="line">        dingRobotRequestBody.setLink(link);</span><br><span class="line">        return dingRobotRequestBody;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 构建at请求</span><br><span class="line">     *</span><br><span class="line">     * @return</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private DingRobotRequestBody.At getnerateAt() &#123;</span><br><span class="line">        DingRobotRequestBody.At at &#x3D; new DingRobotRequestBody.At();</span><br><span class="line">        at.setAtAll(true);</span><br><span class="line">        at.setAtMobiles(Arrays.asList(&quot;xxxxx&quot;, &quot;123456789&quot;));</span><br><span class="line">        return at;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 构建签名方法</span><br><span class="line">     *</span><br><span class="line">     * @param timestamp 时间戳</span><br><span class="line">     * @param secret    秘钥</span><br><span class="line">     * @return</span><br><span class="line">     * @throws Exception</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String generateSign(Long timestamp, String secret) throws Exception &#123;</span><br><span class="line">        String stringToSign &#x3D; timestamp + &quot;\n&quot; + secret;</span><br><span class="line">        Mac mac &#x3D; Mac.getInstance(&quot;HmacSHA256&quot;);</span><br><span class="line">        mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), &quot;HmacSHA256&quot;));</span><br><span class="line">        byte[] signData &#x3D; mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));</span><br><span class="line">        return URLEncoder.encode(new String(Base64.encodeBase64(signData)), &quot;UTF-8&quot;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="构建工具类："><a href="#构建工具类：" class="headerlink" title="构建工具类："></a>构建工具类：</h2><p>下面就上面的单元测试，说明一下个人的基本设计。我们根据思路构建一个支持拿来即用的钉钉工具类。</p>
<h3 id="类结构介绍："><a href="#类结构介绍：" class="headerlink" title="类结构介绍："></a>类结构介绍：</h3><h4 id="Maven依赖："><a href="#Maven依赖：" class="headerlink" title="Maven依赖："></a>Maven依赖：</h4><p>在进行具体的代码编写之前，需要引入对应的依赖，个人秉持最小依赖的原则，使用的三方jar包仅仅为一些测试工具包和Httpclient请求工具包还有最熟悉的fastjson的工具包。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- https:&#x2F;&#x2F;mvnrepository.com&#x2F;artifact&#x2F;org.apache.httpcomponents&#x2F;httpclient --&gt;</span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;org.apache.httpcomponents&lt;&#x2F;groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;httpclient&lt;&#x2F;artifactId&gt;</span><br><span class="line">    &lt;version&gt;4.5.6&lt;&#x2F;version&gt;</span><br><span class="line">&lt;&#x2F;dependency&gt;</span><br><span class="line"></span><br><span class="line">&lt;!-- https:&#x2F;&#x2F;mvnrepository.com&#x2F;artifact&#x2F;com.alibaba&#x2F;fastjson --&gt;</span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;com.alibaba&lt;&#x2F;groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;fastjson&lt;&#x2F;artifactId&gt;</span><br><span class="line">    &lt;version&gt;1.2.75&lt;&#x2F;version&gt;</span><br><span class="line">&lt;&#x2F;dependency&gt;</span><br><span class="line">&lt;!-- https:&#x2F;&#x2F;mvnrepository.com&#x2F;artifact&#x2F;junit&#x2F;junit --&gt;</span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;junit&lt;&#x2F;groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;junit&lt;&#x2F;artifactId&gt;</span><br><span class="line">    &lt;version&gt;4.12&lt;&#x2F;version&gt;</span><br><span class="line">&lt;&#x2F;dependency&gt;</span><br></pre></td></tr></table></figure>

<h4 id="类结构"><a href="#类结构" class="headerlink" title="类结构:"></a>类结构:</h4><p>类结构包含了之前设计思路里面说明的情况，包含请求类，工具类，参数封装和请求对象结构封装等。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">+ DingRobotRequest.java			钉钉请求对象</span><br><span class="line">+ DingRobotRequestAble.java		请求接口，允许发送钉钉请求的接口</span><br><span class="line">+ DingRobotRequestBody.java 	允许发送钉钉请求的接口具体的实现类，比较重要，对接文档的钉钉对象</span><br><span class="line">+ DingRobotRequestMsg.java		废弃对象，但是依然保留s</span><br><span class="line">+ DingRobotResponseMsg.java		请求返回对象</span><br><span class="line">+ DingRobotUtils.java			钉钉请求工具类，非常重要的一个类</span><br><span class="line">+ HttpClientUtil.java			httpclient请求工具类</span><br><span class="line">+ HttpConfig.java				请求参数构建类</span><br><span class="line">+ HttpMethods.java				请求方法类</span><br></pre></td></tr></table></figure>

<h3 id="构建基本的请求环境"><a href="#构建基本的请求环境" class="headerlink" title="构建基本的请求环境"></a>构建基本的请求环境</h3><p>构建基本的请求环境，我们使用对象来封装所有的环境参数，并且使用建造模式构建一个建造器，使用建造来构建我们需要的环境参数，它的使用方式如下：</p>
<ul>
<li>构建请求URL</li>
<li>构建请求accessToken</li>
<li>构建请求msg，<strong>重点</strong>，可以通过构建对应的请求来实现发送不同的信息</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">DingRobotRequest build &#x3D; builder.secret(&quot;SEC2e67120c5e4affa1177ac25fe8dc77ba1c5b49284a9dc7e1888770bc3b76b1fc&quot;)</span><br><span class="line">                .url(&quot;https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send&quot;)</span><br><span class="line">                .accessToken(&quot;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&quot;)</span><br><span class="line">                .msg(generateActionCard()).build();</span><br></pre></td></tr></table></figure>

<p>具体的源代码如下，包含了几个简单的必要参数，以及一个建造器，注意对于构造器的私有化，对外只允许使用构建器进行初始化：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;**</span><br><span class="line"> * @author zxd</span><br><span class="line"> * @version v1.0.0</span><br><span class="line"> * @Package : com.dcc.common.field</span><br><span class="line"> * @Description : 钉钉机器人请求实体类</span><br><span class="line"> * @Create on : 2021&#x2F;2&#x2F;5 15:40</span><br><span class="line"> **&#x2F;</span><br><span class="line">public class DingRobotRequest &#123;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 请求URL</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String url;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * token</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String accessToken;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 秘钥</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String secret;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 请求msg</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private DingRobotRequestBody msg;</span><br><span class="line"></span><br><span class="line">    private DingRobotRequest()&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private DingRobotRequest(Builder builder) &#123;</span><br><span class="line">        this.url &#x3D; builder.url;</span><br><span class="line">        this.accessToken &#x3D; builder.accessToken;</span><br><span class="line">        this.secret &#x3D; builder.secret;</span><br><span class="line">        this.msg &#x3D; builder.msg;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public static class Builder &#123;</span><br><span class="line"></span><br><span class="line">        private String url;</span><br><span class="line">        private String accessToken;</span><br><span class="line">        private String secret;</span><br><span class="line">        private DingRobotRequestBody msg;</span><br><span class="line"></span><br><span class="line">        public DingRobotRequest.Builder url(String url)&#123;</span><br><span class="line">            this.url &#x3D; url;</span><br><span class="line">            return this;</span><br><span class="line">        &#125;</span><br><span class="line">        public DingRobotRequest.Builder accessToken(String accessToken)&#123;</span><br><span class="line">            this.accessToken &#x3D; accessToken;</span><br><span class="line">            return this;</span><br><span class="line">        &#125;</span><br><span class="line">        public DingRobotRequest.Builder secret(String secret)&#123;</span><br><span class="line">            this.secret &#x3D; secret;</span><br><span class="line">            return this;</span><br><span class="line">        &#125;</span><br><span class="line">        public DingRobotRequest.Builder msg(DingRobotRequestBody msg)&#123;</span><br><span class="line">            this.msg &#x3D; msg;</span><br><span class="line">            return this;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public DingRobotRequest build()&#123;</span><br><span class="line">            return new DingRobotRequest(this);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String getUrl() &#123;</span><br><span class="line">        return url;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setUrl(String url) &#123;</span><br><span class="line">        this.url &#x3D; url;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String getAccessToken() &#123;</span><br><span class="line">        return accessToken;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setAccessToken(String accessToken) &#123;</span><br><span class="line">        this.accessToken &#x3D; accessToken;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String getSecret() &#123;</span><br><span class="line">        return secret;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setSecret(String secret) &#123;</span><br><span class="line">        this.secret &#x3D; secret;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public DingRobotRequestBody getMsg() &#123;</span><br><span class="line">        return msg;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setMsg(DingRobotRequestBody msg) &#123;</span><br><span class="line">        this.msg &#x3D; msg;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public String toString() &#123;</span><br><span class="line">        return &quot;DingRobotRequest&#123;&quot; +</span><br><span class="line">                &quot;url&#x3D;&#39;&quot; + url + &#39;\&#39;&#39; +</span><br><span class="line">                &quot;, accessToken&#x3D;&#39;&quot; + accessToken + &#39;\&#39;&#39; +</span><br><span class="line">                &quot;, secret&#x3D;&#39;&quot; + secret + &#39;\&#39;&#39; +</span><br><span class="line">                &quot;, msg&#x3D;&#39;&quot; + msg + &#39;\&#39;&#39; +</span><br><span class="line">                &#39;&#125;&#39;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="构建请求参数"><a href="#构建请求参数" class="headerlink" title="构建请求参数"></a>构建请求参数</h3><p>下面是请求参数的构建案例，我们可以使用链式调用的方式构建不同的request请求：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;**</span><br><span class="line">    * 钉钉机器人的默认配置</span><br><span class="line">    *</span><br><span class="line">    * @param dingRobotRequest    钉钉机器人请求对象</span><br><span class="line">    * @param dingRobotRequestMsg 钉钉机器人请求实体</span><br><span class="line">    * @return</span><br><span class="line">    *&#x2F;</span><br><span class="line">   private static HttpConfig buildDefaultHttpConfig(DingRobotRequest dingRobotRequest, DingRobotRequestAble dingRobotRequestMsg) &#123;</span><br><span class="line">       return HttpConfig.custom().headers(defaultBasicHeader())</span><br><span class="line">               .url(dingRobotRequest.getUrl())</span><br><span class="line">               .encoding(&quot;UTF-8&quot;)</span><br><span class="line">               .method(HttpMethods.POST)</span><br><span class="line">               .json(JSON.toJSONString(dingRobotRequestMsg));</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>

<p>从上面的案例可以看到下面对于请求配置类，构建<code>HttpConfig</code>请求，同样类似构建器进行对象的参数构建，我们定义了基本的请求<code>encoding</code>、请求<code>header</code>，请求方法参数，请求的context等对应的参数配置。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;**</span><br><span class="line"> * 请求配置类</span><br><span class="line"> *</span><br><span class="line"> *&#x2F;</span><br><span class="line">public class HttpConfig &#123;</span><br><span class="line"></span><br><span class="line">    private HttpConfig() &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 传入参数特定类型</span><br><span class="line">    public static final String ENTITY_STRING &#x3D; &quot;$ENTITY_STRING$&quot;;</span><br><span class="line">    public static final String ENTITY_MULTIPART &#x3D; &quot;$ENTITY_MULTIPART$&quot;;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 获取实例</span><br><span class="line">     *</span><br><span class="line">     * @return</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public static HttpConfig custom() &#123;</span><br><span class="line">        return new HttpConfig();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * HttpClient对象</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private HttpClient client;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * Header头信息</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private Header[] headers;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 是否返回response的headers</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private boolean isReturnRespHeaders;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 请求方法</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private HttpMethods method &#x3D; HttpMethods.GET;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 请求方法名称</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String methodName;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 用于cookie操作</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private HttpContext context;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 传递参数</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private Map&lt;String, Object&gt; map;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 以json格式作为输入参数</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String json;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 输入输出编码</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String encoding &#x3D; Charset.defaultCharset().displayName();</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 输入编码</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String inenc;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 输出编码</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String outenc;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 解决多线程下载时，strean被close的问题</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private static final ThreadLocal&lt;OutputStream&gt; outs &#x3D; new ThreadLocal&lt;OutputStream&gt;();</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 解决多线程处理时，url被覆盖问题</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private static final ThreadLocal&lt;String&gt; urls &#x3D; new ThreadLocal&lt;String&gt;();</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * HttpClient对象</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig client(HttpClient client) &#123;</span><br><span class="line">        this.client &#x3D; client;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 资源url</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig url(String url) &#123;</span><br><span class="line">        urls.set(url);</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * Header头信息</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig headers(Header[] headers) &#123;</span><br><span class="line">        this.headers &#x3D; headers;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * Header头信息(是否返回response中的headers)</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig headers(Header[] headers, boolean isReturnRespHeaders) &#123;</span><br><span class="line">        this.headers &#x3D; headers;</span><br><span class="line">        this.isReturnRespHeaders &#x3D; isReturnRespHeaders;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 请求方法</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig method(HttpMethods method) &#123;</span><br><span class="line">        this.method &#x3D; method;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 请求方法</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig methodName(String methodName) &#123;</span><br><span class="line">        this.methodName &#x3D; methodName;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * cookie操作相关</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig context(HttpContext context) &#123;</span><br><span class="line">        this.context &#x3D; context;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 传递参数</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig map(Map&lt;String, Object&gt; map) &#123;</span><br><span class="line">        synchronized (getClass()) &#123;</span><br><span class="line">            if (this.map &#x3D;&#x3D; null || map &#x3D;&#x3D; null) &#123;</span><br><span class="line">                this.map &#x3D; map;</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                this.map.putAll(map);</span><br><span class="line">                ;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 以json格式字符串作为参数</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig json(String json) &#123;</span><br><span class="line">        this.json &#x3D; json;</span><br><span class="line">        map &#x3D; new HashMap&lt;String, Object&gt;();</span><br><span class="line">        map.put(ENTITY_STRING, json);</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 上传文件时用到</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig files(String[] filePaths) &#123;</span><br><span class="line">        return files(filePaths, &quot;file&quot;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 上传文件时用到</span><br><span class="line">     *</span><br><span class="line">     * @param filePaths 待上传文件所在路径</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig files(String[] filePaths, String inputName) &#123;</span><br><span class="line">        return files(filePaths, inputName, false);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 上传文件时用到</span><br><span class="line">     *</span><br><span class="line">     * @param filePaths                     待上传文件所在路径</span><br><span class="line">     * @param inputName                     即file input 标签的name值，默认为file</span><br><span class="line">     * @param forceRemoveContentTypeChraset</span><br><span class="line">     * @return</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig files(String[] filePaths, String inputName, boolean forceRemoveContentTypeChraset) &#123;</span><br><span class="line">        synchronized (getClass()) &#123;</span><br><span class="line">            if (this.map &#x3D;&#x3D; null) &#123;</span><br><span class="line">                this.map &#x3D; new HashMap&lt;String, Object&gt;();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        map.put(ENTITY_MULTIPART, filePaths);</span><br><span class="line">        map.put(ENTITY_MULTIPART + &quot;.name&quot;, inputName);</span><br><span class="line">        map.put(ENTITY_MULTIPART + &quot;.rmCharset&quot;, forceRemoveContentTypeChraset);</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 输入输出编码</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig encoding(String encoding) &#123;</span><br><span class="line">        &#x2F;&#x2F;设置输入输出</span><br><span class="line">        inenc(encoding);</span><br><span class="line">        outenc(encoding);</span><br><span class="line">        this.encoding &#x3D; encoding;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 输入编码</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig inenc(String inenc) &#123;</span><br><span class="line">        this.inenc &#x3D; inenc;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 输出编码</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig outenc(String outenc) &#123;</span><br><span class="line">        this.outenc &#x3D; outenc;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 输出流对象</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public HttpConfig out(OutputStream out) &#123;</span><br><span class="line">        outs.set(out);</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public HttpClient client() &#123;</span><br><span class="line">        return client;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public Header[] headers() &#123;</span><br><span class="line">        return headers;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public boolean isReturnRespHeaders() &#123;</span><br><span class="line">        return isReturnRespHeaders;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String url() &#123;</span><br><span class="line">        return urls.get();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public HttpMethods method() &#123;</span><br><span class="line">        return method;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String methodName() &#123;</span><br><span class="line">        return methodName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public HttpContext context() &#123;</span><br><span class="line">        return context;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public Map&lt;String, Object&gt; map() &#123;</span><br><span class="line">        return map;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String json() &#123;</span><br><span class="line">        return json;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String encoding() &#123;</span><br><span class="line">        return encoding;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String inenc() &#123;</span><br><span class="line">        return inenc &#x3D;&#x3D; null ? encoding : inenc;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String outenc() &#123;</span><br><span class="line">        return outenc &#x3D;&#x3D; null ? encoding : outenc;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public OutputStream out() &#123;</span><br><span class="line">        return outs.get();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="使用JAVA代码发送请求"><a href="#使用JAVA代码发送请求" class="headerlink" title="使用JAVA代码发送请求"></a>使用JAVA代码发送请求</h3><p>之前说明，我们使用最常用的<code>Httpclient</code>进行设计请求，根据<code>Httpclient</code>请求工具包构建一个基本的工具类：</p>
<blockquote>
<p>这个类是一个很难复用和扩展的高耦合类，并且设计不是非常良好。</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;**</span><br><span class="line"> * httpclient 请求工具封装类</span><br><span class="line"> *&#x2F;</span><br><span class="line">public class HttpClientUtil &#123;</span><br><span class="line"></span><br><span class="line">	public static String doGet(String url, Map&lt;String, String&gt; param) &#123;</span><br><span class="line"></span><br><span class="line">		&#x2F;&#x2F; 创建Httpclient对象</span><br><span class="line">		CloseableHttpClient httpclient &#x3D; HttpClients.createDefault();</span><br><span class="line"></span><br><span class="line">		String resultString &#x3D; &quot;&quot;;</span><br><span class="line">		CloseableHttpResponse response &#x3D; null;</span><br><span class="line">		try &#123;</span><br><span class="line">			&#x2F;&#x2F; 创建uri</span><br><span class="line">			URIBuilder builder &#x3D; new URIBuilder(url);</span><br><span class="line">			if (param !&#x3D; null) &#123;</span><br><span class="line">				for (String key : param.keySet()) &#123;</span><br><span class="line">					builder.addParameter(key, param.get(key));</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;</span><br><span class="line">			URI uri &#x3D; builder.build();</span><br><span class="line"></span><br><span class="line">			&#x2F;&#x2F; 创建http GET请求</span><br><span class="line">			HttpGet httpGet &#x3D; new HttpGet(uri);</span><br><span class="line"></span><br><span class="line">			&#x2F;&#x2F; 执行请求</span><br><span class="line">			response &#x3D; httpclient.execute(httpGet);</span><br><span class="line">			&#x2F;&#x2F; 判断返回状态是否为200</span><br><span class="line">			if (response.getStatusLine().getStatusCode() &#x3D;&#x3D; 200) &#123;</span><br><span class="line">				resultString &#x3D; EntityUtils.toString(response.getEntity(), &quot;UTF-8&quot;);</span><br><span class="line">			&#125;</span><br><span class="line">		&#125; catch (Exception e) &#123;</span><br><span class="line">			e.printStackTrace();</span><br><span class="line">		&#125; finally &#123;</span><br><span class="line">			try &#123;</span><br><span class="line">				if (response !&#x3D; null) &#123;</span><br><span class="line">					response.close();</span><br><span class="line">				&#125;</span><br><span class="line">				httpclient.close();</span><br><span class="line">			&#125; catch (IOException e) &#123;</span><br><span class="line">				e.printStackTrace();</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		return resultString;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	public static String doGet(String url) &#123;</span><br><span class="line">		return doGet(url, null);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	public static String doPost(String url, Map&lt;String, String&gt; param) &#123;</span><br><span class="line">		&#x2F;&#x2F; 创建Httpclient对象</span><br><span class="line">		CloseableHttpClient httpClient &#x3D; HttpClients.createDefault();</span><br><span class="line">		CloseableHttpResponse response &#x3D; null;</span><br><span class="line">		String resultString &#x3D; &quot;&quot;;</span><br><span class="line">		try &#123;</span><br><span class="line">			&#x2F;&#x2F; 创建Http Post请求</span><br><span class="line">			HttpPost httpPost &#x3D; new HttpPost(url);</span><br><span class="line">			&#x2F;&#x2F; 创建参数列表</span><br><span class="line">			if (param !&#x3D; null) &#123;</span><br><span class="line">				List&lt;NameValuePair&gt; paramList &#x3D; new ArrayList&lt;&gt;();</span><br><span class="line">				for (String key : param.keySet()) &#123;</span><br><span class="line">					paramList.add(new BasicNameValuePair(key, param.get(key)));</span><br><span class="line">				&#125;</span><br><span class="line">				&#x2F;&#x2F; 模拟表单</span><br><span class="line">				UrlEncodedFormEntity entity &#x3D; new UrlEncodedFormEntity(paramList);</span><br><span class="line">				httpPost.setEntity(entity);</span><br><span class="line">			&#125;</span><br><span class="line">			&#x2F;&#x2F; 执行http请求</span><br><span class="line">			response &#x3D; httpClient.execute(httpPost);</span><br><span class="line">			resultString &#x3D; EntityUtils.toString(response.getEntity(), &quot;utf-8&quot;);</span><br><span class="line">		&#125; catch (Exception e) &#123;</span><br><span class="line">			e.printStackTrace();</span><br><span class="line">		&#125; finally &#123;</span><br><span class="line">			try &#123;</span><br><span class="line">				response.close();</span><br><span class="line">			&#125; catch (IOException e) &#123;</span><br><span class="line"></span><br><span class="line">				e.printStackTrace();</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		return resultString;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	public static String doPost(String url) &#123;</span><br><span class="line">		return doPost(url, null);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	public static String doPostJson(String url, String json) &#123;</span><br><span class="line">		&#x2F;&#x2F; 创建Httpclient对象</span><br><span class="line">		CloseableHttpClient httpClient &#x3D; HttpClients.createDefault();</span><br><span class="line">		CloseableHttpResponse response &#x3D; null;</span><br><span class="line">		String resultString &#x3D; &quot;&quot;;</span><br><span class="line">		try &#123;</span><br><span class="line">			&#x2F;&#x2F; 创建Http Post请求</span><br><span class="line">			HttpPost httpPost &#x3D; new HttpPost(url);</span><br><span class="line">			&#x2F;&#x2F; 创建请求内容</span><br><span class="line">			StringEntity entity &#x3D; new StringEntity(json, ContentType.APPLICATION_JSON);</span><br><span class="line">			httpPost.setEntity(entity);</span><br><span class="line">			&#x2F;&#x2F; 执行http请求</span><br><span class="line">			response &#x3D; httpClient.execute(httpPost);</span><br><span class="line">			resultString &#x3D; EntityUtils.toString(response.getEntity(), &quot;utf-8&quot;);</span><br><span class="line">		&#125; catch (Exception e) &#123;</span><br><span class="line">			e.printStackTrace();</span><br><span class="line">		&#125; finally &#123;</span><br><span class="line">			try &#123;</span><br><span class="line">				if(response !&#x3D; null)&#123;</span><br><span class="line">					response.close();</span><br><span class="line">				&#125;</span><br><span class="line">			&#125; catch (IOException e) &#123;</span><br><span class="line"></span><br><span class="line">				e.printStackTrace();</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		return resultString;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	&#x2F;**</span><br><span class="line">	 * 根据请求Config 进行请求发送</span><br><span class="line">	 * @param httpConfig</span><br><span class="line">	 * @return</span><br><span class="line">	 *&#x2F;</span><br><span class="line">	public static String send(HttpConfig httpConfig) &#123;</span><br><span class="line">		return doPostJson(httpConfig.url(), httpConfig.json());</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>接着根据请求的结果设计一个钉钉机器人的返回对象，返回对象的设计也比较的简单。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;**</span><br><span class="line"> * @author zxd</span><br><span class="line"> * @version v1.0.0</span><br><span class="line"> * @Package : com.dcc.common.field</span><br><span class="line"> * @Description : 钉钉机器人返回对象</span><br><span class="line"> * @Create on : 2021&#x2F;2&#x2F;5 18:26</span><br><span class="line"> **&#x2F;</span><br><span class="line">public class DingRobotResponseMsg &#123;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 错误码</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String errcode;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 错误信息</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String errmsg;</span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 更多链接</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String more;</span><br><span class="line"></span><br><span class="line">    public DingRobotResponseMsg(String errcode, String errmsg, String more) &#123;</span><br><span class="line">        this.errcode &#x3D; errcode;</span><br><span class="line">        this.errmsg &#x3D; errmsg;</span><br><span class="line">        this.more &#x3D; more;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public DingRobotResponseMsg() &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String getErrcode() &#123;</span><br><span class="line">        return errcode;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String getErrmsg() &#123;</span><br><span class="line">        return errmsg;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String getMore() &#123;</span><br><span class="line">        return more;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setErrcode(String errcode) &#123;</span><br><span class="line">        this.errcode &#x3D; errcode;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setErrmsg(String errmsg) &#123;</span><br><span class="line">        this.errmsg &#x3D; errmsg;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setMore(String more) &#123;</span><br><span class="line">        this.more &#x3D; more;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>最后，也是最重要的，我们要根据钉钉的文档，构建一个所有类型的请求对象类，这个类包含了钉钉文档目前支持的所有类型。内部使用了大量的内部类，客户端需要了解一定的细节才可以具体的调用。下面简要说明一下内容类的基本使用结构。</p>
<ul>
<li>At 艾特对象内部类</li>
<li>Text 文本类型</li>
<li>Link 请求链接类型</li>
<li>MarkDown markdown类型</li>
<li>ActionCard 整体跳转类型</li>
<li>FeedCard 分享卡片类型</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;**</span><br><span class="line"> * @author zxd</span><br><span class="line"> * @version v1.0.0</span><br><span class="line"> * @Package : com.dcc.common.field</span><br><span class="line"> * @Description : 钉钉机器人请求实体对象</span><br><span class="line"> * 请求案例：&#123;&quot;msgtype&quot;: &quot;text&quot;,&quot;text&quot;: &#123;&quot;content&quot;: &quot;自定义具体内容&quot;&#125;&#125;</span><br><span class="line"> * @link &#123;https:&#x2F;&#x2F;developers.dingtalk.com&#x2F;document&#x2F;app&#x2F;custom-robot-access&#125;</span><br><span class="line"> *</span><br><span class="line"> * @Create on : 2021&#x2F;2&#x2F;5 11:55</span><br><span class="line"> **&#x2F;</span><br><span class="line">public class DingRobotRequestBody implements DingRobotRequestAble &#123;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 艾特对象内容</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private At at;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 类型</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private String msgtype;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 文本类型</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private Text text;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 连接类型</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private Link link;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * markdown 类型</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private MarkDown markdown;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 整体跳转ActionCard类型</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private ActionCard actionCard;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * FeedCard类型</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private FeedCard feedCard;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * FeedCard类型</span><br><span class="line">     *</span><br><span class="line">     * msgtype	    String	是	此消息类型为固定feedCard。</span><br><span class="line">     * title	    String	是	单条信息文本。</span><br><span class="line">     * messageURL	String	是	点击单条信息到跳转链接。</span><br><span class="line">     * picURL	    String	是	单条信息后面图片的URL。</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public static class FeedCard&#123;</span><br><span class="line"></span><br><span class="line">        private List&lt;FeedItem&gt; links;</span><br><span class="line"></span><br><span class="line">        &#x2F;**</span><br><span class="line">         * 代表 FeedCard类型 子类型</span><br><span class="line">         *&#x2F;</span><br><span class="line">        public static class FeedItem&#123;</span><br><span class="line"></span><br><span class="line">            private String title;</span><br><span class="line"></span><br><span class="line">            private String messageURL;</span><br><span class="line"></span><br><span class="line">            private String picURL;</span><br><span class="line"></span><br><span class="line">            public String getTitle() &#123;</span><br><span class="line">                return title;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            public void setTitle(String title) &#123;</span><br><span class="line">                this.title &#x3D; title;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            public String getMessageURL() &#123;</span><br><span class="line">                return messageURL;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            public void setMessageURL(String messageURL) &#123;</span><br><span class="line">                this.messageURL &#x3D; messageURL;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            public String getPicURL() &#123;</span><br><span class="line">                return picURL;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            public void setPicURL(String picURL) &#123;</span><br><span class="line">                this.picURL &#x3D; picURL;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public List&lt;FeedItem&gt; getLinks() &#123;</span><br><span class="line">            return links;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setLinks(List&lt;FeedItem&gt; links) &#123;</span><br><span class="line">            this.links &#x3D; links;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 整体跳转ActionCard类型</span><br><span class="line">     * msgtype	        String	是	消息类型，此时固定为：actionCard。</span><br><span class="line">     * title	        String	是	首屏会话透出的展示内容。</span><br><span class="line">     * text	            String	是	markdown格式的消息。</span><br><span class="line">     * singleTitle	    String	是	单个按钮的标题。</span><br><span class="line">     *</span><br><span class="line">     * 注意 设置此项和singleURL后，btns无效。</span><br><span class="line">     *</span><br><span class="line">     * singleURL	    String	是	点击singleTitle按钮触发的URL。</span><br><span class="line">     * btnOrientation	String	否	0：按钮竖直排列1：按钮横向排列</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public static class ActionCard&#123;</span><br><span class="line"></span><br><span class="line">        private String title;</span><br><span class="line"></span><br><span class="line">        private String text;</span><br><span class="line"></span><br><span class="line">        private String btnOrientation;</span><br><span class="line"></span><br><span class="line">        private String singleTitle;</span><br><span class="line"></span><br><span class="line">        private String singleURL;</span><br><span class="line"></span><br><span class="line">        public String getTitle() &#123;</span><br><span class="line">            return title;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setTitle(String title) &#123;</span><br><span class="line">            this.title &#x3D; title;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public String getText() &#123;</span><br><span class="line">            return text;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setText(String text) &#123;</span><br><span class="line">            this.text &#x3D; text;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public String getBtnOrientation() &#123;</span><br><span class="line">            return btnOrientation;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setBtnOrientation(String btnOrientation) &#123;</span><br><span class="line">            this.btnOrientation &#x3D; btnOrientation;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public String getSingleTitle() &#123;</span><br><span class="line">            return singleTitle;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setSingleTitle(String singleTitle) &#123;</span><br><span class="line">            this.singleTitle &#x3D; singleTitle;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public String getSingleURL() &#123;</span><br><span class="line">            return singleURL;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setSingleURL(String singleURL) &#123;</span><br><span class="line">            this.singleURL &#x3D; singleURL;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 艾特类</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public static class At&#123;</span><br><span class="line"></span><br><span class="line">        &#x2F;**</span><br><span class="line">         * 是否通知全部人</span><br><span class="line">         *&#x2F;</span><br><span class="line">        private boolean atAll;</span><br><span class="line"></span><br><span class="line">        &#x2F;**</span><br><span class="line">         * 需要@的手机号数组</span><br><span class="line">         *&#x2F;</span><br><span class="line">        private List&lt;String&gt; atMobiles;</span><br><span class="line"></span><br><span class="line">        public boolean isAtAll() &#123;</span><br><span class="line">            return atAll;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setAtAll(boolean atAll) &#123;</span><br><span class="line">            this.atAll &#x3D; atAll;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public List&lt;String&gt; getAtMobiles() &#123;</span><br><span class="line">            return atMobiles;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setAtMobiles(List&lt;String&gt; atMobiles) &#123;</span><br><span class="line">            this.atMobiles &#x3D; atMobiles;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     *</span><br><span class="line">     * markdown 类型， 可以发送markdown 的语法格式</span><br><span class="line">     * msgtype	    String	是	消息类型，此时固定为：markdown。</span><br><span class="line">     * title	    String	是	首屏会话透出的展示内容。</span><br><span class="line">     * text	        String	是	markdown格式的消息。</span><br><span class="line">     * atMobiles	Array	否	被@人的手机号。 注意 在text内容里要有@人的手机号。</span><br><span class="line">     * isAtAll	Boolean	否	是否@所有人。</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public static class MarkDown&#123;</span><br><span class="line"></span><br><span class="line">        private String title;</span><br><span class="line"></span><br><span class="line">        private String text;</span><br><span class="line"></span><br><span class="line">        public String getTitle() &#123;</span><br><span class="line">            return title;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setTitle(String title) &#123;</span><br><span class="line">            this.title &#x3D; title;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public String getText() &#123;</span><br><span class="line">            return text;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setText(String text) &#123;</span><br><span class="line">            this.text &#x3D; text;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 钉钉请求：链接类型</span><br><span class="line">     *</span><br><span class="line">         msgtype	    String	是	消息类型，此时固定为：link。</span><br><span class="line">         title	        String	是	消息标题。</span><br><span class="line">         text	        String	是	消息内容。如果太长只会部分展示。</span><br><span class="line">         messageUrl	    String	是	点击消息跳转的URL。</span><br><span class="line">         picUrl	        String	否	图片URL。</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public static class Link&#123;</span><br><span class="line"></span><br><span class="line">        private String text;</span><br><span class="line"></span><br><span class="line">        private String messageUrl;</span><br><span class="line"></span><br><span class="line">        private String picUrl;</span><br><span class="line"></span><br><span class="line">        private String title;</span><br><span class="line"></span><br><span class="line">        public String getText() &#123;</span><br><span class="line">            return text;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setText(String text) &#123;</span><br><span class="line">            this.text &#x3D; text;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public String getMessageUrl() &#123;</span><br><span class="line">            return messageUrl;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setMessageUrl(String messageUrl) &#123;</span><br><span class="line">            this.messageUrl &#x3D; messageUrl;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public String getPicUrl() &#123;</span><br><span class="line">            return picUrl;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setPicUrl(String picUrl) &#123;</span><br><span class="line">            this.picUrl &#x3D; picUrl;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public String getTitle() &#123;</span><br><span class="line">            return title;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setTitle(String title) &#123;</span><br><span class="line">            this.title &#x3D; title;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 钉钉请求：纯文本类型</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public static class Text&#123;</span><br><span class="line"></span><br><span class="line">        &#x2F;**</span><br><span class="line">         * text请求内容</span><br><span class="line">         *&#x2F;</span><br><span class="line">        private String content;</span><br><span class="line"></span><br><span class="line">        public String getContent() &#123;</span><br><span class="line">            return content;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        public void setContent(String content) &#123;</span><br><span class="line">            this.content &#x3D; content;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public void setMsgType(String msgtype) &#123;</span><br><span class="line">        this.msgtype &#x3D; msgtype;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public void setText(Text text) &#123;</span><br><span class="line">        this.text &#x3D; text;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public void setLink(Link link) &#123;</span><br><span class="line">        this.link &#x3D; link;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public void setMarkDown(MarkDown markDown) &#123;</span><br><span class="line">        this.markdown &#x3D; markDown;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public void setActionCard(ActionCard actionCard) &#123;</span><br><span class="line">        this.actionCard &#x3D; actionCard;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public void setFeedCard(FeedCard feedCard) &#123;</span><br><span class="line">        this.feedCard &#x3D; feedCard;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public At getAt() &#123;</span><br><span class="line">        return at;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setAt(At at) &#123;</span><br><span class="line">        this.at &#x3D; at;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String getMsgtype() &#123;</span><br><span class="line">        return msgtype;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public Text getText() &#123;</span><br><span class="line">        return text;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public Link getLink() &#123;</span><br><span class="line">        return link;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public MarkDown getMarkdown() &#123;</span><br><span class="line">        return markdown;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public ActionCard getActionCard() &#123;</span><br><span class="line">        return actionCard;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public FeedCard getFeedCard() &#123;</span><br><span class="line">        return feedCard;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>插曲：在生成具体的钉钉对应请求对象时候，我们构建了一个对应的接口</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;**</span><br><span class="line"> * @author zxd</span><br><span class="line"> * @version v1.0.0</span><br><span class="line"> * @Package : com.zxd.interview.dingrobot</span><br><span class="line"> * @Description : 允许发送钉钉请求的接口</span><br><span class="line"> * @Create on : 2021&#x2F;2&#x2F;7 11:45</span><br><span class="line"> **&#x2F;</span><br><span class="line">public interface DingRobotRequestAble &#123;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 所有的子类需要集成该接口</span><br><span class="line">     * @return</span><br><span class="line">     *&#x2F;</span><br><span class="line">    void setMsgType(String msgType);</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 普通文本类型</span><br><span class="line">     * @param text</span><br><span class="line">     *&#x2F;</span><br><span class="line">    void setText(DingRobotRequestBody.Text text);</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * link类型</span><br><span class="line">     * @param link</span><br><span class="line">     *&#x2F;</span><br><span class="line">    void setLink(DingRobotRequestBody.Link link);</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * markdown 类型</span><br><span class="line">     * @param markDown</span><br><span class="line">     *&#x2F;</span><br><span class="line">    void setMarkDown(DingRobotRequestBody.MarkDown markDown);</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 整体跳转ActionCard类型</span><br><span class="line">     * @param actionCard</span><br><span class="line">     *&#x2F;</span><br><span class="line">    void setActionCard(DingRobotRequestBody.ActionCard actionCard);</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * feedcard 类型</span><br><span class="line">     * @param feedCard</span><br><span class="line">     *&#x2F;</span><br><span class="line">    void setFeedCard(DingRobotRequestBody.FeedCard feedCard);</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</blockquote>
<h3 id="构建钉钉请求工具类"><a href="#构建钉钉请求工具类" class="headerlink" title="构建钉钉请求工具类"></a>构建钉钉请求工具类</h3><p>介绍完上面所有的辅助对象之后，我们着手构建核心的钉钉请求工具类，钉钉的请求工具类包含了基本的请求步骤，提供对外的请求方法，调用者根据请求对象构建对应的请求参数即可，从下面的代码可以看到最核心的方法是<code>notifyRobot</code>这个方法，这个方法非常简单，内部的逻辑分为如下的几步：</p>
<ul>
<li>构建请求环境参数</li>
<li>构建请求的URL和对应的携带参数</li>
<li>构建具体的请求参数</li>
<li>将请求返回的JSON字符串进行转化</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;**</span><br><span class="line"> * @author zxd</span><br><span class="line"> * @version v1.0.0</span><br><span class="line"> * @Package : com.dcc.common.utils</span><br><span class="line"> * @Description : 钉钉机器人工具类</span><br><span class="line"> * @Create on : 2021&#x2F;2&#x2F;4 00:11</span><br><span class="line"> **&#x2F;</span><br><span class="line">public class DingRobotUtils &#123;</span><br><span class="line"></span><br><span class="line">    private static final Logger LOGGER &#x3D; LoggerFactory.getLogger(DingRobotUtils.class);</span><br><span class="line"></span><br><span class="line">    public static DingRobotResponseMsg notifyRobot(DingRobotRequest dingRobotRequest, long currentTimeMillis) throws Exception &#123;</span><br><span class="line">        Map&lt;String, Object&gt; param &#x3D; buildParam(dingRobotRequest, currentTimeMillis);</span><br><span class="line">        String s &#x3D; buildParamUrl(param);</span><br><span class="line">        &#x2F;&#x2F; 钉钉的请求参数需要拼接到URL链接</span><br><span class="line">        dingRobotRequest.setUrl(String.format(&quot;%s?%s&quot;, dingRobotRequest.getUrl(), s));</span><br><span class="line">        HttpConfig httpConfig &#x3D; buildDefaultHttpConfig(dingRobotRequest, dingRobotRequest.getMsg());</span><br><span class="line">        return parseResponse(notifyRobot(httpConfig));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 转化为对应对象</span><br><span class="line">     *</span><br><span class="line">     * @param notifyRobot 转化JSON</span><br><span class="line">     * @return</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private static DingRobotResponseMsg parseResponse(String notifyRobot) &#123;</span><br><span class="line">        try &#123;</span><br><span class="line">            return JSON.parseObject(notifyRobot, DingRobotResponseMsg.class);</span><br><span class="line">        &#125; catch (Exception e) &#123;</span><br><span class="line">            LOGGER.error(&quot;类型转化失败，失败原因为:&#123;&#125;&quot;, e.getMessage());</span><br><span class="line">            throw e;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 按照自定时间戳进行通知</span><br><span class="line">     *</span><br><span class="line">     * @param dingRobotRequest 钉钉机器人请求</span><br><span class="line">     * @throws Exception</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public static DingRobotResponseMsg notifyRobot(DingRobotRequest dingRobotRequest) throws Exception &#123;</span><br><span class="line">        long currentTimeMillis &#x3D; System.currentTimeMillis();</span><br><span class="line">        return notifyRobot(dingRobotRequest, currentTimeMillis);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 构建请求环境参数</span><br><span class="line">     *</span><br><span class="line">     * @param dingRobotRequest  请求request</span><br><span class="line">     * @param currentTimeMillis 当前时间戳</span><br><span class="line">     * @return</span><br><span class="line">     * @throws Exception</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private static Map&lt;String, Object&gt; buildParam(DingRobotRequest dingRobotRequest, long currentTimeMillis) throws Exception &#123;</span><br><span class="line">        Map&lt;String, Object&gt; param &#x3D; new HashMap&lt;&gt;(3);</span><br><span class="line">        param.put(&quot;access_token&quot;, dingRobotRequest.getAccessToken());</span><br><span class="line">        param.put(&quot;timestamp&quot;, currentTimeMillis);</span><br><span class="line">        param.put(&quot;sign&quot;, generateSign(currentTimeMillis, dingRobotRequest.getSecret()));</span><br><span class="line">        return param;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 钉钉机器人的默认配置</span><br><span class="line">     *</span><br><span class="line">     * @param dingRobotRequest    钉钉机器人请求对象</span><br><span class="line">     * @param dingRobotRequestMsg 钉钉机器人请求实体</span><br><span class="line">     * @return</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private static HttpConfig buildDefaultHttpConfig(DingRobotRequest dingRobotRequest, DingRobotRequestAble dingRobotRequestMsg) &#123;</span><br><span class="line">        return HttpConfig.custom().headers(defaultBasicHeader())</span><br><span class="line">                .url(dingRobotRequest.getUrl())</span><br><span class="line">                .encoding(&quot;UTF-8&quot;)</span><br><span class="line">                .method(HttpMethods.POST)</span><br><span class="line">                .json(JSON.toJSONString(dingRobotRequestMsg));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 默认headers配置</span><br><span class="line">     *</span><br><span class="line">     * @return</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private static Header[] defaultBasicHeader() &#123;</span><br><span class="line">        Header[] headers &#x3D; new Header[1];</span><br><span class="line">        headers[0] &#x3D; new BasicHeader(&quot;Content-Type&quot;, &quot;application&#x2F;json&quot;);</span><br><span class="line">        return headers;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private static String notifyRobot(HttpConfig httpConfig) throws Exception &#123;</span><br><span class="line">        String send &#x3D; &quot;&quot;;</span><br><span class="line">        try &#123;</span><br><span class="line">            send &#x3D; HttpClientUtil.send(httpConfig);</span><br><span class="line">        &#125; catch (Exception e) &#123;</span><br><span class="line">            LOGGER.error(&quot;HTTPClient请求发送失败, 失败原因为:&#123;&#125;&quot;, e.getMessage());</span><br><span class="line">            throw e;</span><br><span class="line">        &#125;</span><br><span class="line">        return send;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 根据时间戳和秘钥生成一份签名</span><br><span class="line">     *</span><br><span class="line">     * @param timestamp 时间戳</span><br><span class="line">     * @param secret    秘钥</span><br><span class="line">     * @return</span><br><span class="line">     * @throws Exception</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private static String generateSign(Long timestamp, String secret) throws Exception &#123;</span><br><span class="line">        String stringToSign &#x3D; timestamp + &quot;\n&quot; + secret;</span><br><span class="line">        Mac mac &#x3D; Mac.getInstance(&quot;HmacSHA256&quot;);</span><br><span class="line">        mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), &quot;HmacSHA256&quot;));</span><br><span class="line">        byte[] signData &#x3D; mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));</span><br><span class="line">        return URLEncoder.encode(new String(Base64.encodeBase64(signData)), &quot;UTF-8&quot;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;**</span><br><span class="line">     * 构建URL参数</span><br><span class="line">     *</span><br><span class="line">     * @param param 请求MAP参数</span><br><span class="line">     * @return</span><br><span class="line">     *&#x2F;</span><br><span class="line">    private static String buildParamUrl(Map&lt;String, Object&gt; param) &#123;</span><br><span class="line">        if (null &#x3D;&#x3D; param || param.size() &#x3D;&#x3D; 0) &#123;</span><br><span class="line">            return &quot;&quot;;</span><br><span class="line">        &#125;</span><br><span class="line">        StringBuilder stringBuilder &#x3D; new StringBuilder();</span><br><span class="line">        param.forEach((key, value) -&gt; &#123;</span><br><span class="line">            stringBuilder.append(key).append(&quot;&#x3D;&quot;).append(value);</span><br><span class="line">            stringBuilder.append(&quot;&amp;&quot;);</span><br><span class="line">        &#125;);</span><br><span class="line">        stringBuilder.deleteCharAt(stringBuilder.length() - 1);</span><br><span class="line">        return stringBuilder.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>下面是本工具类的使用方式，只需要传入环境参数并且传入必须的请求msg，就可以直接发送请求并且返回对应的结果。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"> DingRobotRequest.Builder builder &#x3D; new DingRobotRequest.Builder();</span><br><span class="line">DingRobotRequest build &#x3D; builder.secret(&quot;SEC2e67120c5e4affa1177ac25fe8dc77ba1c5b49284a9dc7e1888770bc3b76b1fc&quot;)</span><br><span class="line">    .url(&quot;https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send&quot;)</span><br><span class="line">    .accessToken(&quot;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&quot;)</span><br><span class="line">    .msg(generateActionCard()).build();</span><br><span class="line">try &#123;</span><br><span class="line">    DingRobotResponseMsg dingRobotResponseMsg &#x3D; DingRobotUtils.notifyRobot(build);</span><br><span class="line">    System.err.println(JSON.toJSONString(dingRobotResponseMsg));</span><br><span class="line">&#125; catch (Exception e) &#123;</span><br><span class="line">    e.printStackTrace();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>至此，一个工具类构建就完成了，整个构建的过程还是十分简单的。这次的工具代码也是不断进行小改动的成果。个人的代码水平功底有限，如果有什么意见欢迎点评。</p>
<h1 id="问题汇总："><a href="#问题汇总：" class="headerlink" title="问题汇总："></a>问题汇总：</h1><p>下面汇总了一些个人使用钉钉花的时间比较多的点。</p>
<blockquote>
<p>吐槽：其实个人感觉钉钉的机器人在错误码这一块并不是特别的直观，下面说下个人踩到的一些小坑。</p>
</blockquote>
<h2 id="关于加签测试机器人出现31000的问题"><a href="#关于加签测试机器人出现31000的问题" class="headerlink" title="关于加签测试机器人出现31000的问题"></a>关于加签测试机器人出现<code>31000</code>的问题</h2><p>如果在添加机器人的时候进行加签是需要加入对应的<code>sign</code>和<code>timestamp</code>参数才可以测试成功，这里个人卡了一会儿才明白设计者的意图，虽然很好理解，但是对于第一次使用的人不是十分友好，同时在文档里面明显对于这一块的描述比较少，这里提供一下个人的小坑说明：</p>
<p>首先，我们需要根据请求的时间戳和秘钥生成签名</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">.....</span><br><span class="line">&#x2F;**</span><br><span class="line"> * 构建当前的系统时间戳</span><br><span class="line"> *&#x2F;</span><br><span class="line">@Test</span><br><span class="line">public void generateSystemCurrentTime() throws Exception &#123;</span><br><span class="line">    long l &#x3D; System.currentTimeMillis();</span><br><span class="line">    String secret &#x3D; &quot;SEC2e67120c5e4affa1177ac25fe8dc77ba1c5b49284a9dc7e1888770bc3b76b1fc&quot;;</span><br><span class="line">    String sign &#x3D; generateSign(l, secret);</span><br><span class="line">    System.out.println(&quot;timestamp &#x3D; &quot;+ l);</span><br><span class="line">    System.out.println(&quot;sign &#x3D; &quot; + sign);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">private String generateSign(Long timestamp, String secret) throws Exception &#123;</span><br><span class="line">    String stringToSign &#x3D; timestamp + &quot;\n&quot; + secret;</span><br><span class="line">    Mac mac &#x3D; Mac.getInstance(&quot;HmacSHA256&quot;);</span><br><span class="line">    mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), &quot;HmacSHA256&quot;));</span><br><span class="line">    byte[] signData &#x3D; mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));</span><br><span class="line">    return URLEncoder.encode(new String(Base64.encodeBase64(signData)), &quot;UTF-8&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">....</span><br></pre></td></tr></table></figure>

<p>生成签名之后，我们需要把<strong>时间戳</strong>和<strong>签名</strong>放入到请求的URL参数里面，测试方可通过：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https:&#x2F;&#x2F;oapi.dingtalk.com&#x2F;robot&#x2F;send?access_token&#x3D;381c2f405e0f906fd556b27cea9f66864120860b5d8b117bb046e10b6599b050&amp;timestamp&#x3D;1613212722591&amp;sign&#x3D;SsKKlkvwM%2F4tsCPE6YoGls8vgkQqWJGHYpvWbW7hTGM%3D</span><br></pre></td></tr></table></figure>

<blockquote>
<p>提示：还是注意一下，在设置里面增加了加签</p>
</blockquote>
<h1 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h1><p>本文主要为记录个人使用钉钉的一些心得体会，以及以此编写了一个工具包方便以后有需要的时候可以直接拿来使用。</p>
<p>钉钉机器人的使用就告一段落了，目前工具类已经应用到公司项目正常的发送请求通知。后续看心情对于HttpClient请求工具类重构，但是目前个人还在参考和学习设计记录，发现可以拆分的对象还是不少的。包含请求方法，请求Header，请求编码等各种形式的转化。</p>
<p>最后，个人最近从<strong>《代码简洁之道》</strong>里面学习了很多有用的编程技巧和编写代码的细节问题，推荐读者看一看这本书，对于写出一个好代码和好注释或者想要学习改良自己的代码都是很有好处的，后续个人也会写一篇学习笔记，感兴趣的可以关注一波。</p>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/kity@2.0.4/dist/kity.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/kityminder-core@1.4.50/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://cdn.jsdelivr.net/npm/hexo-simple-mindmap@0.2.0/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/hexo-simple-mindmap@0.2.0/dist/mindmap.min.css">
    </div>

    
    
    
        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>lazytime
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://whitestore.top/2021/02/14/dingding/" title="钉钉机器人简单使用">https://whitestore.top/2021/02/14/dingding/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <span class="exturl" data-url="aHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLzQuMC96aC1DTg=="><i class="fa fa-fw fa-creative-commons"></i>BY-NC</span> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/%E5%85%B6%E4%BB%96/" rel="tag"># 其他</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2021/02/14/nativebook/" rel="prev" title="《生活需要断舍离》读书笔记">
      <i class="fa fa-chevron-left"></i> 《生活需要断舍离》读书笔记
    </a></div>
      <div class="post-nav-item">
    <a href="/2021/03/07/factorymethod2/" rel="next" title="浅谈设计模式 - 工厂模式（六）">
      浅谈设计模式 - 工厂模式（六） <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          
    <div class="comments" id="valine-comments"></div>

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#钉钉自定义机器人简单使用"><span class="nav-number">1.</span> <span class="nav-text">钉钉自定义机器人简单使用</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#前言："><span class="nav-number">2.</span> <span class="nav-text">前言：</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#文章目的："><span class="nav-number">3.</span> <span class="nav-text">文章目的：</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#钉钉文档："><span class="nav-number">4.</span> <span class="nav-text">钉钉文档：</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#如何创建一个机器人"><span class="nav-number">5.</span> <span class="nav-text">如何创建一个机器人</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#创建一个自定义机器人"><span class="nav-number">5.1.</span> <span class="nav-text">创建一个自定义机器人</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#测试机器人是否可以正常使用"><span class="nav-number">5.2.</span> <span class="nav-text">测试机器人是否可以正常使用</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#windows-验证方式："><span class="nav-number">5.2.1.</span> <span class="nav-text">windows 验证方式：</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#linux-验证方式："><span class="nav-number">5.2.2.</span> <span class="nav-text">linux 验证方式：</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#编写工具类"><span class="nav-number">6.</span> <span class="nav-text">编写工具类</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#工具类的代码地址"><span class="nav-number">6.1.</span> <span class="nav-text">工具类的代码地址</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#构建工具类的思路"><span class="nav-number">6.2.</span> <span class="nav-text">构建工具类的思路</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#单元测试"><span class="nav-number">6.3.</span> <span class="nav-text">单元测试</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#构建工具类："><span class="nav-number">6.4.</span> <span class="nav-text">构建工具类：</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#类结构介绍："><span class="nav-number">6.4.1.</span> <span class="nav-text">类结构介绍：</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#Maven依赖："><span class="nav-number">6.4.1.1.</span> <span class="nav-text">Maven依赖：</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#类结构"><span class="nav-number">6.4.1.2.</span> <span class="nav-text">类结构:</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#构建基本的请求环境"><span class="nav-number">6.4.2.</span> <span class="nav-text">构建基本的请求环境</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#构建请求参数"><span class="nav-number">6.4.3.</span> <span class="nav-text">构建请求参数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#使用JAVA代码发送请求"><span class="nav-number">6.4.4.</span> <span class="nav-text">使用JAVA代码发送请求</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#构建钉钉请求工具类"><span class="nav-number">6.4.5.</span> <span class="nav-text">构建钉钉请求工具类</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#问题汇总："><span class="nav-number">7.</span> <span class="nav-text">问题汇总：</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#关于加签测试机器人出现31000的问题"><span class="nav-number">7.1.</span> <span class="nav-text">关于加签测试机器人出现31000的问题</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#结尾"><span class="nav-number">8.</span> <span class="nav-text">结尾</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">阿东</p>
  <div class="site-description" itemprop="description">随遇而安</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">239</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">36</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">37</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2xhenlUaW1lcw==" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;lazyTimes"><i class="fa fa-fw fa-github"></i>GitHub</span>
      </span>
      <span class="links-of-author-item">
        <span class="exturl" data-url="bWFpbHRvOjEwOTc0ODM1MDhAcXEuY29t" title="E-Mail → mailto:1097483508@qq.com"><i class="fa fa-fw fa-envelope"></i>E-Mail</span>
      </span>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title">
      <i class="fa fa-fw fa-link"></i>
      友情链接
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <span class="exturl" data-url="aHR0cHM6Ly93d3cuNTJwb2ppZS5jbi9ob21lLnBocD9tb2Q9c3BhY2UmdWlkPTE0OTc3MTgmZG89dGhyZWFkJnZpZXc9bWUmZnJvbT1zcGFjZQ==" title="https:&#x2F;&#x2F;www.52pojie.cn&#x2F;home.php?mod&#x3D;space&amp;uid&#x3D;1497718&amp;do&#x3D;thread&amp;view&#x3D;me&amp;from&#x3D;space">吾爱破解</span>
        </li>
        <li class="links-of-blogroll-item">
          <span class="exturl" data-url="aHR0cHM6Ly9qdWVqaW4uaW0vdXNlci8yOTk5MTIzNDUyNjI2MzY2" title="https:&#x2F;&#x2F;juejin.im&#x2F;user&#x2F;2999123452626366">掘金</span>
        </li>
        <li class="links-of-blogroll-item">
          <span class="exturl" data-url="aHR0cHM6Ly9zZWdtZW50ZmF1bHQuY29tL3UvbGF6eXRpbWVz" title="https:&#x2F;&#x2F;segmentfault.com&#x2F;u&#x2F;lazytimes">思否</span>
        </li>
    </ul>
  </div>

      </div>

      <div class="wechat_OA">
        <span>欢迎关注我的公众号</span>
        <br>
          <!-- 这里添加你的二维码图片 -->
        <img src ="https://adong-picture.oss-cn-shenzhen.aliyuncs.com/adong/wechat_channel.jpg">
      </div>
        <div class="back-to-top motion-element">
          <i class="fa fa-arrow-up"></i>
          <span>0%</span>
        </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">阿东</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-area-chart"></i>
    </span>
      <span class="post-meta-item-text">站点总字数：</span>
    <span title="站点总字数">2m</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span class="post-meta-item-text">站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">29:50</span>
</div>
  <div class="powered-by">由 <span class="exturl theme-link" data-url="aHR0cHM6Ly9oZXhvLmlv">Hexo</span> & <span class="exturl theme-link" data-url="aHR0cHM6Ly90aGVtZS1uZXh0Lm9yZw==">NexT.Gemini</span> 强力驱动
  </div>

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
  <script src="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  




  
<script src="/js/local-search.js"></script>













  

  


<script>
NexT.utils.loadComments(document.querySelector('#valine-comments'), () => {
  NexT.utils.getScript('//unpkg.com/valine/dist/Valine.min.js', () => {
    var GUEST = ['nick', 'mail', 'link'];
    var guest = 'nick,mail,link';
    guest = guest.split(',').filter(item => {
      return GUEST.includes(item);
    });
    new Valine({
      el         : '#valine-comments',
      verify     : false,
      notify     : true,
      appId      : 'qMUpEEvBgXaMDD1b0ftgi9xr-gzGzoHsz',
      appKey     : 'UCdfT4Rfih6MO6y8DI4fstf6',
      placeholder: "Just go go",
      avatar     : 'mm',
      meta       : guest,
      pageSize   : '10' || 10,
      visitor    : false,
      lang       : 'zh-CN' || 'zh-cn',
      path       : location.pathname,
      recordIP   : false,
      serverURLs : ''
    });
  }, window.Valine);
});
</script>

</body>
</html>
